from tkinter import Frame, W, Entry, StringVar, Button, DISABLED, Label
import re
from functools import partial
from InputDefinition import InputDefinition
from gui.DefinitionGui import DefinitionGui
from Detect import Detect
from PIL import ImageTk
import time
from gui.LocaterGui import LocatorGui


class InputGui(DefinitionGui):
	def __init__(self, parent, root, listener):
		super().__init__(root, listener)
		self.parent = parent
		self.int_reg = re.compile('^[0-9]+$')

		self.definitions = InputDefinition.read()
		self._set_definitions(self.definitions)

		self._make_definition_gui()
		self.active_frame = None
		self.detector = Detect()

		self.locator = LocatorGui(parent, self.content_frame, self.manual_callback)
		self.locator.grid(row=0, column=1, sticky=W)

	def _make_definition_gui(self):
		self.definition_details = {}
		for definition in self.definitions:
			key = definition.content['name']
			self.definition_details[key] = {
				'frame': Frame(self.content_frame),
				'locations': {}
			}
			self._fill_definition_frame(self.definition_details[key]['frame'], key, definition)
			self.definition_details[key]['frame'].grid(row=0, column=0, sticky=W)
			self.definition_details[key]['frame'].grid_remove()

	def _fill_definition_frame(self, frame, key, definition):
		vcmd = (frame.register(self._validate_int), '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')

		for index, listener in enumerate(definition.get_listeners()):
			location = listener.get('location')
			detect = listener.get('detect')

			x_var = StringVar()
			x_entry = Entry(frame, textvariable=x_var, width=5, validate='key', validatecommand=vcmd)
			x_entry.grid(row=index, column=0, sticky=W)

			y_var = StringVar()
			y_entry = Entry(frame, textvariable=y_var, width=5)
			y_entry.grid(row=index, column=1, sticky=W)

			self.definition_details[key]['locations'][index] = {
				'x': x_var,
				'y': y_var,
			}

			if location is not None:
				x_var.set(location['x'])
				y_var.set(location['y'])

			auto_button = Button(frame)
			auto_button['text'] = 'Auto'
			if detect is None:
				auto_button['state'] = DISABLED
			auto_button['command'] = partial(self._auto, key, index)
			auto_button.grid(row=index, column=2)

			manual_button = Button(frame)
			manual_button['text'] = 'Manuel'
			manual_button['command'] = partial(self._manual, key, index)
			manual_button.grid(row=index, column=3)

		index += 1
		use_button = Button(frame)
		use_button['text'] = 'Use'
		use_button['command'] = partial(self._use, key)
		use_button.grid(row=index, column=0, columnspan=4, sticky=W)

	# '%d'	Action code: 0 for an attempted deletion, 1 for an attempted insertion, or -1 if the callback was called for focus in, focus out, or a change to the textvariable.
	# '%i'	When the user attempts to insert or delete text, this argument will be the index of the beginning of the insertion or deletion. If the callback was due to focus in, focus out, or a change to the textvariable, the argument will be -1.
	# '%P'	The value that the text will have if the change is allowed.
	# '%s'	The text in the entry before the change.
	# '%S'	If the call was due to an insertion or deletion, this argument will be the text being inserted or deleted.
	# '%v'	The current value of the widget's validate option.
	# '%V'	The reason for this callback: one of 'focusin', 'focusout', 'key', or 'forced' if the textvariable was changed.
	# '%W'	The name of the widget.
	def _validate_int(self, d, i, P, s, S, v, V, W):
		if self.int_reg.match(P) is not None:
			return True
		return False

	def _get_definition_from_name(self, name):
		for definition in self.definitions:
			if definition.content['name'] == name:
				return definition

	def _auto(self, key, index):
		definition = self._get_definition_from_name(key)
		detectet_location, error = definition.get_single_detect(index)
		if error is None:
			self.definition_details[key]['locations'][index]['x'].set(detectet_location[0])
			self.definition_details[key]['locations'][index]['y'].set(detectet_location[1])
		else:
			self.parent.set_status(error)

	def _manual(self, key, index):
		self.locator.start(key, index)

	def manual_callback(self, x, y, key, index):
		self.definition_details[key]['locations'][index]['x'].set(x)
		self.definition_details[key]['locations'][index]['y'].set(y)

	def _use(self, key):
		definition = self._get_definition_from_name(key)

		for index, listener in enumerate(definition.get_listeners()):
			x = int(self.definition_details[key]['locations'][index]['x'].get())
			y = int(self.definition_details[key]['locations'][index]['y'].get())
			listener['location'] = {'x': x, 'y': y}

	def _select(self):
		super()._select()
		if self.active_frame is not None:
			self.active_frame.grid_remove()

		definition = self.listener.input
		key = definition.content['name']
		frame = self.definition_details[key]['frame']
		frame.grid()
		self.active_frame = frame
